package com.stark.commons.spring.web.boot.config;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

import com.stark.commons.spring.web.boot.properties.WebProperties;
import com.stark.commons.spring.web.boot.properties.WebProperties.CorsProperties;
import com.stark.commons.spring.web.interceptor.MonitorInterceptor;
import com.stark.commons.spring.web.interceptor.SecurityInterceptor;
import com.stark.commons.spring.web.support.exception.HttpRequestMethodNotSupportedExceptionHandler;
import com.stark.commons.spring.web.support.exception.ServletRequestBindingExceptionHandler;

import lombok.extern.slf4j.Slf4j;

/**
 * Web Mvc 自动化配置。
 * @author Ben
 * @since 1.0.0
 * @version 1.0.0
 */
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(WebProperties.class)
@Slf4j
public class WebMvcAutoConfig implements WebMvcConfigurer {
	
	@Autowired
	private WebProperties webProperties;
	
	@Autowired(required = false)
	private List<HandlerInterceptor> interceptors;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		if (webProperties.getMonitorStandard() > 0) {
			registry.addInterceptor(new MonitorInterceptor(webProperties.getMonitorStandard()));
		}
		if (webProperties.isSecurityCheck()) {
			registry.addInterceptor(new SecurityInterceptor());
		}
		
		if (CollectionUtils.isNotEmpty(interceptors)) {
			interceptors.forEach(interceptor -> registry.addInterceptor(interceptor));
		}
	}
	
	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
		resolvers
			.stream()
			.filter(resolver -> resolver instanceof ExceptionHandlerExceptionResolver)
			.forEach(resolver -> {
				ExceptionHandlerExceptionResolver exceptionResolver = (ExceptionHandlerExceptionResolver) resolver;
				exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
			});
	}
	
	@Bean
	@ConditionalOnProperty(prefix = "web.cors", name = "enabled", havingValue = "true")
	public CorsFilter corsFilter() {
		CorsProperties corsProperties = webProperties.getCors();
		CorsConfiguration conf = new CorsConfiguration();
		conf.setAllowedOrigins(Arrays.asList(corsProperties.getAllowedOrigins().split(",")));
		conf.setAllowedMethods(Arrays.asList(corsProperties.getAllowedMethods().split(",")));
		conf.setAllowedHeaders(Arrays.asList(corsProperties.getAllowedHeaders().split(",")));
		conf.setAllowCredentials(corsProperties.isAllowCredentials());
		conf.setMaxAge(corsProperties.getMaxAge());
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration(corsProperties.getPathPattern(), conf);
		CorsFilter corsFilter = new CorsFilter(source);
		log.warn("\n-->web.cors.enabled=true, 配置跨域:"
				+ "\n   allowedOrigins=" + corsProperties.getAllowedOrigins()
				+ "\n   allowedMethods=" + corsProperties.getAllowedMethods()
				+ "\n   allowedHeaders=" + corsProperties.getAllowedHeaders()
				+ "\n   allowCredentials=" + corsProperties.isAllowCredentials()
				+ "\n   maxAge=" + corsProperties.getMaxAge());
		return corsFilter;
	}
	
	@Bean
	@ConditionalOnClass(name = "org.springframework.web.HttpRequestMethodNotSupportedException")
	@ConditionalOnMissingBean(name = "httpRequestMethodNotSupportedExceptionHandler")
	public HttpRequestMethodNotSupportedExceptionHandler httpRequestMethodNotSupportedExceptionHandler() {
		return new HttpRequestMethodNotSupportedExceptionHandler();
	}
	
	@Bean
	@ConditionalOnClass(name = "org.springframework.web.bind.ServletRequestBindingException")
	@ConditionalOnMissingBean(name = "servletRequestBindingExceptionHandler")
	public ServletRequestBindingExceptionHandler servletRequestBindingExceptionHandler() {
		return new ServletRequestBindingExceptionHandler();
	}
	
}
